package com.zyl.add;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author zhaoyl
 * @date 2024/5/16 11:04
 * @description 说明
 *
 * 模拟“人满发车”的场景
 * 利用CyclicBarrier的计数器能够重置，屏障可以重复使用的特性，可以支持类似“人满发车”的场景
 *
 * CyclicBarrier 流程
 * 主要是的流程：
 * 获取锁 如果 count != 0 就进入阻塞；
 * 进入阻塞之前，首先需要进入条件队列，然后释放锁，最后阻塞；
 * 如果 count != 0 会进行一个唤醒，将所有的条件队列中的节点转换为阻塞队列；
 * 被唤醒过后会进行锁的获取，如果锁获取失败，会进入 lock 的阻塞队列；
 * 如果锁获取成功，进行锁的释放，以及唤醒，同步队列中的线程。
 */
public class CyclicBarrierTest2 {
    public static void main(String[] args) {
        AtomicInteger counter = new AtomicInteger();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5, 5, 1000, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(100),
                (r) -> new Thread(r, counter.addAndGet(1) + " 号 "),
                new ThreadPoolExecutor.AbortPolicy());

        CyclicBarrier cyclicBarrier = new CyclicBarrier(5,
                () -> System.out.println("司机：开始出发~~"));

        for (int i = 0; i < 5; i++) {
            threadPoolExecutor.submit(new Runner(cyclicBarrier));
        }

    }
    static class Runner extends Thread{
        private CyclicBarrier cyclicBarrier;
        public Runner (CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                int sleepMills = ThreadLocalRandom.current().nextInt(1000);
                Thread.sleep(sleepMills);
                System.out.println(Thread.currentThread().getName() + " 乘客已经上车, 准备共用时： " + sleepMills + "ms" + cyclicBarrier.getNumberWaiting());
                cyclicBarrier.await();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }catch(BrokenBarrierException e){
                e.printStackTrace();
            }
        }
    }

}
